home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Dev
/
GNU-SMALLTALK.lha
/
mstcallin.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-15
|
12KB
|
609 lines
/***********************************************************************
*
* C Callin facility
*
* This module provides the routines necessary to allow C code to
* invoke Smalltalk messages on objects.
*
***********************************************************************/
/***********************************************************************
*
* Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
* Written by Steve Byrne.
*
* This file is part of GNU Smalltalk.
*
* GNU Smalltalk is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 1, or (at your option) any later
* version.
*
* GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* GNU Smalltalk; see the file COPYING. If not, write to the Free Software
* Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
***********************************************************************/
/*
* Change Log
* ============================================================================
* Author Date Change
* sbb 1 Jan 92 Fixed to auto-initialize Smalltalk when the public
* routines are invoked.
*
* sbb 31 Dec 91 Created.
*
*/
#include <varargs.h>
#include <stdio.h>
#include "mst.h"
#include "mstlib.h"
#include "mstinterp.h"
#include "mstcallin.h"
#include "mstdict.h"
#include "mstsym.h"
#include "mstoop.h"
/* Simple control over oop registry size */
#define INITIAL_REGISTRY_SIZE 100
/*
* The registry of OOPs which have been passed to C code. A vector of
* of oops, running from 0 to registryIndex, some of which may be nilOOP.
* the current allocated size of the registry is registrySize, and the
* registry may be reallocated to a larger size as need. The registry
* is examined at GC time to ensure that OOPs that C code knows about don't
* go away. "C code" here means user level C code, not Smalltalk internal
* code.
*/
static OOP *oopRegistry;
static int registrySize, registryIndex;
OOP msgSend(va_alist)
va_dcl
{
va_list args;
OOP receiver, selector, anArg, result;
int numArgs;
va_start(args);
if (!smalltalkInitialized) { initSmalltalk(); }
receiver = va_arg(args, OOP);
selector = va_arg(args, OOP);
prepareExecutionEnvironment();
pushOOP(receiver);
for (numArgs = 0; (anArg = va_arg(args, OOP)) != nil; numArgs++) {
pushOOP(anArg);
}
sendMessage(selector, numArgs, false);
interpret();
result = popOOP();
finishExecutionEnvironment();
return (result);
}
OOP strMsgSend(va_alist)
va_dcl
{
va_list args;
OOP receiver, selector, anArg, result;
int numArgs;
va_start(args);
if (!smalltalkInitialized) { initSmalltalk(); }
receiver = va_arg(args, OOP);
selector = internString(va_arg(args, char *));
prepareExecutionEnvironment();
pushOOP(receiver);
for (numArgs = 0; (anArg = va_arg(args, OOP)) != nil; numArgs++) {
pushOOP(anArg);
}
sendMessage(selector, numArgs, false);
interpret();
result = popOOP();
finishExecutionEnvironment();
return (result);
}
#ifdef looks_goofy_to_me /* Tue Dec 31 20:41:01 1991 */
/**/voidPtr cMsgSend(va_alist)
/**/va_dcl
/**/{
/**/ va_list args;
/**/ OOP receiver, selector, anArg, result;
/**/ int numArgs, bool;
/**/ char *argStr, *s;
/**/ union {
/**/ voidPtr v;
/**/ float f;
/**/ } conv;
/**/
/**/ va_start(args);
/**/
/**/ argStr = va_arg(args, char *);
/**/ selector = internString(va_arg(args, char *));
/**/
/**/ prepareExecutionEnvironment();
/**/
/**/ s = argStr + 2; /* <type>= */
/**/ for (numArgs = -1; *s; numArgs++, s++) {
/**/ switch (*s) {
/**/ case 'i':
/**/ pushInt(va_arg(args, long));
/**/ break;
/**/
/**/ case 'f':
/**/ anArg = floatNew(va_arg(args, double));
/**/ pushOOP(anArg);
/**/ break;
/**/
/**/ case 'b':
/**/ if (va_arg(args, int)) {
/**/ pushOOP(trueOOP);
/**/ } else {
/**/ pushOOP(falseOOP);
/**/ }
/**/ break;
/**/
/**/ case 'c':
/**/ anArg = charOOPAt(va_arg(args, char));
/**/ pushOOP(anArg);
/**/ break;
/**/
/**/ case 'C':
/**/ anArg = cObjectNew(va_arg(args, voidPtr));
/**/ pushOOP(anArg);
/**/ break;
/**/
/**/ case 's':
/**/ anArg = stringNew(va_arg(args, char *));
/**/ pushOOP(anArg);
/**/ break;
/**/
/**/ case 'S':
/**/ anArg = internString(va_arg(args, char *));
/**/ pushOOP(anArg);
/**/ break;
/**/ }
/**/ }
/**/
/**/ sendMessage(selector, numArgs, false);
/**/ interpret();
/**/ result = popOOP();
/**/ finishExecutionEnvironment();
/**/
/**/ switch (*argStr) {
/**/ case 'i':
/**/ return ((voidPtr)toInt(result));
/**/
/**/ case 'c':
/**/ return ((voidPtr)charOOPValue(result));
/**/
/**/ case 'C':
/**/ return (cObjectValue(result));
/**/
/**/ case 's':
/**/ return (toCString(result));
/**/
/**/ case 'b':
/**/ return ((voidPtr)(result == trueOOP));
/**/
/**/ case 'f':
/**/ conv.f = floatOOPValue(result);
/**/ return (conv.v);
/**/
/**/ default:
/**/ return (result);
/**/ }
/**/}
#endif /* looks_goofy_to_me Tue Dec 31 20:41:01 1991 */
/* like printf */
void msgSendf(va_alist)
va_dcl
{
va_list args;
OOP receiver, selector, anArg, result;
int numArgs, bool;
voidPtr *resultPtr;
char *fmt, *fp, *s, selectorBuf[256];
va_start(args);
if (!smalltalkInitialized) { initSmalltalk(); }
resultPtr = va_arg(args, voidPtr *);
fmt = va_arg(args, char *);
prepareExecutionEnvironment();
numArgs = -1;
for (s = selectorBuf, fp = &fmt[2]; *fp; fp++) {
if (*fp == '%') {
fp++;
numArgs++;
switch (*fp) {
case 'i':
pushInt(va_arg(args, long));
break;
case 'f':
anArg = floatNew(va_arg(args, double));
pushOOP(anArg);
break;
case 'b':
if (va_arg(args, int)) {
pushOOP(trueOOP);
} else {
pushOOP(falseOOP);
}
break;
case 'c':
anArg = charOOPAt(va_arg(args, char));
pushOOP(anArg);
break;
case 'C':
anArg = cObjectNew(va_arg(args, voidPtr));
pushOOP(anArg);
break;
case 's':
anArg = stringNew(va_arg(args, char *));
pushOOP(anArg);
break;
case 'S':
anArg = internString(va_arg(args, char *));
pushOOP(anArg);
break;
case 'o':
anArg = va_arg(args, OOP);
pushOOP(anArg);
break;
case '%':
*s++ = '%';
numArgs--;
break;
}
} else if (*fp != ' ' && *fp != '\t') {
*s++ = *fp;
}
}
*s = '\0';
selector = internString(selectorBuf);
sendMessage(selector, numArgs, false);
interpret();
result = popOOP();
finishExecutionEnvironment();
if (resultPtr) {
switch (fmt[1]) {
case 'i':
*(int *)resultPtr = toInt(result);
break;
case 'c':
*(char *)resultPtr = charOOPValue(result);
break;
case 'C':
*resultPtr = cObjectValue(result);
break;
case 's':
*(char **)resultPtr = (char *)toCString(result);
break;
case 'b':
*(int *)resultPtr = (result == trueOOP);
break;
case 'f':
*(double *)resultPtr = floatOOPValue(result);
break;
case 'o':
default:
*(OOP *)resultPtr = result;
break;
}
}
}
void evalCode(str)
char *str;
{
if (!smalltalkInitialized) { initSmalltalk(); }
prepareExecutionEnvironment();
initLexer(false);
pushCString(str);
yyparse();
popStream(false);
finishExecutionEnvironment();
}
/*
* OOP evalExpr(str)
*
* Description
*
* Evaluate a single Smalltalk expression and return the result.
*
* Inputs
*
* str : A Smalltalk method body. Can have local variables, but no
* parameters. This is much like the immediate expression
* evaluation that the command interpreter provides.
*
* Outputs
*
*
*/
OOP evalExpr(str)
char *str;
{
OOP result;
if (!smalltalkInitialized) { initSmalltalk(); }
/* !!! not done yet */
prepareExecutionEnvironment();
initLexer(false);
pushCString(str);
yyparse();
popStream(false);
result = finishExecutionEnvironment();
return (result);
}
/***********************************************************************
*
* Conversion *to* Smalltalk datatypes routines
*
***********************************************************************/
OOP intToOOP(i)
long i;
{
if (!smalltalkInitialized) { initSmalltalk(); }
return (fromInt(i));
}
OOP floatToOOP(f)
double f;
{
return (registerOOP(floatNew(f)));
}
OOP boolToOOP(b)
int b;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (b) {
return (trueOOP);
} else {
return (falseOOP);
}
}
OOP charToOOP(c)
char c;
{
if (!smalltalkInitialized) { initSmalltalk(); }
return (charOOPAt(c));
}
/* !!! Add in byteArray support sometime soon */
OOP stringToOOP(str)
char *str;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (str == nil) {
return (nilOOP);
} else {
return (registerOOP(stringNew(str)));
}
}
OOP symbolToOOP(str)
char *str;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (str == nil) {
return (nilOOP);
} else {
return (internString(str));
}
}
OOP cObjectToOOP(co)
voidPtr co;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (co == nil) {
return (nilOOP);
} else {
return (registerOOP(cObjectNew(co)));
}
}
/***********************************************************************
*
* Conversion *from* Smalltalk datatypes routines
*
***********************************************************************/
/* ### need a type inquiry routine */
long OOPToInt(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
return (toInt(oop));
}
double OOPToFloat(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
return (floatOOPValue(oop));
}
int OOPToBool(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
return (oop == trueOOP);
}
char OOPToChar(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
return (charOOPValue(oop));
}
char *OOPToString(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (isNil(oop)) {
return (nil);
} else {
return ((char *)toCString(oop));
}
}
/* !!! add in byteArray support soon */
voidPtr OOPToCObject(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (isNil(oop)) {
return (nil);
} else {
return (cObjectValue(oop));
}
}
/***********************************************************************
*
* Bookkeeping routines
*
***********************************************************************/
void initOOPRegistry()
{
oopRegistry = (OOP *)malloc(INITIAL_REGISTRY_SIZE * sizeof(OOP));
registrySize = INITIAL_REGISTRY_SIZE;
registryIndex = 0;
}
OOP registerOOP(oop)
OOP oop;
{
if (!smalltalkInitialized) { initSmalltalk(); }
if (registryIndex >= registrySize) {
registrySize += INITIAL_REGISTRY_SIZE;
oopRegistry = (OOP *)realloc(oopRegistry, registrySize);
}
oopRegistry[registryIndex++] = oop;
return (oop);
}
void unregisterOOP(oop)
OOP oop;
{
int i;
if (!smalltalkInitialized) { initSmalltalk(); }
for (i = 0; i < registryIndex; i++) {
if (oopRegistry[i] == oop) {
oopRegistry[i] = nilOOP;
}
}
}
/*
* void copyRegisteredOOPs()
*
* Description
*
* Called at gcFlip time, copies registered objects to the new space,
* and compresses out unregistered objects and those which are duplicates.
*
*/
void copyRegisteredOOPs()
{
int maxIndex, i;
OOP oop;
maxIndex = 0;
for (i = 0; i < registryIndex; i++) {
oop = oopRegistry[i];
if (!isNil(oop) && inFromSpace(oop)) {
oopRegistry[maxIndex++] = oop;
localMaybeMoveOOP(oop);
}
}
registryIndex = maxIndex;
}